#pragma once

#include <iostream>
#include <string.h>
#include <functional>
#include <cstdint>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <memory>
#include <unistd.h>
#include "InetAddr.hpp"
#include "Log.hpp"
using namespace log_ns;
const static int gblcklog = 3;
class Socket;
using SockPtr = std::shared_ptr<Socket>;
enum
{
    SOCKET_ERROR = 1,
    Bind_ERROR,
    LISTEN_ERR
};
class Socket
{
public:
    // 创建Socket
    virtual void CreateSocket() = 0;
    // bind（Ip,Port）
    virtual void BindAddress(uint16_t port) = 0;
    // listen：监听套接字
    virtual void ListenSocket(int blcklog = gblcklog) = 0;
    // 接受连接
    virtual SockPtr AcceptSocket(InetAddr *cliaddr) = 0;
    // 连接服务器
    virtual bool Connect(std::string &peerip, uint16_t port) = 0;
    virtual int Sockfd() = 0;
    virtual void Close() = 0;

public:
    void BuildServerListenSocket(uint16_t port)
    {
        CreateSocket();
        BindAddress(port);
        ListenSocket(gblcklog);
    }
    void BuildCilentSocket(std::string &peerip, uint16_t port)
    {
        CreateSocket();
        Connect(peerip, port);
    }
};

class TcpSocket : public Socket
{
public:
    TcpSocket()
        : _sockfd(-1)
    {
    }
    TcpSocket(int sockfd)
        : _sockfd(sockfd)
    {
        // BuildCilentSocket();
    }
    ~TcpSocket()
    {
        if (_sockfd > 0)
        {
            ::close(_sockfd);
        }
    }

public:
    void CreateSocket() override
    {
        _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            std::cerr << "Create Socket Error" << std::endl;
            exit(-1);
        }
    }
    void BindAddress(uint16_t port) override
    {
        struct sockaddr_in local_addr;
        memset(&local_addr, 0, sizeof(local_addr));
        local_addr.sin_family = AF_INET;
        local_addr.sin_port = htons(port);
        local_addr.sin_addr.s_addr = INADDR_ANY;
        int n = ::bind(_sockfd, (struct sockaddr *)&local_addr, sizeof(local_addr));
        if (n < 0)
        {
            std::cerr << "Bind Error" << std::endl;
            exit(-1);
        }
    }
    void ListenSocket(int blcklog) override
    {
        if (::listen(_sockfd, blcklog) < 0)
        {
            std::cerr << "Listen Error" << std::endl;

            exit(-1);
        }
    }
    SockPtr AcceptSocket(InetAddr *cliaddr)
    {
        // 因为要接受的客户端
        struct sockaddr_in client_addr;
        socklen_t addr_len = sizeof(client_addr);
        int client_sockfd = ::accept(_sockfd, (struct sockaddr *)&client_addr, &addr_len);
        if (client_sockfd < 0)
        {
            std::cerr << "Accept Error" << std::endl;
            exit(-1);
        }
        *cliaddr = InetAddr(client_addr);
        return std::make_shared<TcpSocket>(client_sockfd);
    }
    bool Connect(std::string &peerip, uint16_t port) override
    {
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(port);
        // inet_pton 函数的作用是将点分十进制的IP地址（例如 "192.168.1.1"）转换为用于网络传输的数值格式。
        // 这个函数接受三个参数：地址族（AF_INET 对于IPv4，AF_INET6 对于IPv6
        // 一个指向IP地址字符串的指针，以及一个指向存储转换结果的缓冲区的指针。
        // 如果转换成功，函数返回1；如果输入的地址不是有效的表达式，则返回0；如果发生错误，则返回-1。
        ::inet_pton(AF_INET, peerip.c_str(), &server.sin_addr);
        int n = ::connect(_sockfd, (struct sockaddr *)&server, sizeof(server));
        if (n < 0)
        {
            std::cerr << "connect socket error" << std::endl;
            return false;
        }
        return true;
    }
    int Sockfd()
    {
        return _sockfd;
    }
    void Close()
    {
        if (_sockfd > 0)
        {
            ::close(_sockfd);
            _sockfd = -1;
        }

    }

private:
    int _sockfd;
};
